from typing import List, Union

from helper.FileHelper import TextFile
from helper.ObjectHelper import Object
from helper.texter.Language import Language, language_text
from helper.texter.Replacer import bs, b0, b1, b2

wrapped_block_mark = "\n\t"


class CodeBlock(Object):
    def __init__(
            self,
            language: Language = language_text,
            template: str = "",
            replace_list: Union[None, List] = None,
    ):
        if replace_list is None:
            replace_list = []
        self.language: Language = language
        self.template: str = template
        self.replace_list: List[Union[str, CodeBlock]] = replace_list
        #
        self.wrapped_block: Union[None, CodeBlock] = None
        if_find_wrapped_block_mark = False
        for i in range(len(self.replace_list)):
            if if_find_wrapped_block_mark:
                break
            re_new = f"{bs[i]}"
            re_old = f"{wrapped_block_mark}{re_new}"
            if self.template.__contains__(re_old):
                self.wrapped_block = self.replace_list[i]
                self.template = self.template.replace(re_old, re_new)
                if_find_wrapped_block_mark = True
        #
        pass

    def add_block(
            self,
            *replace_list,
    ):
        for i in replace_list:
            self.replace_list.append(i)

    def add_line_block(self):
        self.add_block("\n")

    def add_remark_block(
            self,
            *replace_list: str,
    ):
        list_len = len(replace_list)
        if list_len == 0:
            return ""
        if list_len == 1 and replace_list[0] == "":
            return ""
        cb = get_empty_block()
        for i in replace_list:
            cb.add_block(self.get_remark_block(i))
        self.add_block(cb)

    def get_str(
            self,
            tab_num: int = 0,
            if_l_strip: bool = True,
    ) -> str:
        now_tab_str = "\t" * tab_num
        res = self.template
        res = res.replace(f"\n", f"\n{now_tab_str}")
        if_begin_not_contains = False
        for i, v in enumerate(self.replace_list):
            if if_begin_not_contains:
                if_contain_i = False
            else:
                if_contain_i = self.if_contain_i(i)
                if not if_contain_i:
                    if_begin_not_contains = True
            v_str = ""
            if isinstance(v, str):
                v_str = v.replace(f"\n", f"\n{now_tab_str}")
            elif isinstance(v, CodeBlock):
                v_str = v.get_str(
                    tab_num=tab_num + if_contain_i,
                    if_l_strip=False,
                )
            if if_contain_i:
                res = res.replace(bs[i], v_str)
            else:
                res += v_str
        if if_l_strip:
            res = res.lstrip("\n")
        return res

    def print_code(
            self,
            text_file: TextFile = None,
            if_l_strip: bool = True,
    ):
        print(
            f"{self.get_str(if_l_strip=if_l_strip, )}",
            end="",
            file=text_file,
        )

    def if_contain_i(self, index: int):
        return self.template.__contains__(bs[index])

    @staticmethod
    def get_block(
            language: Language = language_text,
            template: str = "",
            *replace_list,
    ):
        return CodeBlock(language, template, list(replace_list))

    def get_remark_block(
            self,
            content: str,
    ):
        return CodeBlock.get_block(self.language, f"{self.language.remark_prefix}{b0}", content)

    def get_fun_call_block(
            self,
            method_name: str,
            args,
            if_line=True,
    ):
        cb = get_block(
            f"{b0}({b1})",
            method_name,
            args,
        )
        if not if_line:
            return cb
        else:
            return get_line_block(
                cb,
                self.language.line_end
            )


def get_block(
        template: str = "",
        *replace_list: Union[str, CodeBlock],
):
    return CodeBlock.get_block(language_text, template, *replace_list)


def get_empty_block(
        *replace_list: Union[str, CodeBlock],
):
    return get_block("", *replace_list)


def get_line_block(
        v: Union[str, CodeBlock] = "",
        line_end: str = ""
):
    cb = get_block(
        f"\n{b0}{line_end}",
        v,
    )
    return cb


def get_args_block(
        *replace_list: Union[str, CodeBlock],
):
    return get_block(
        ", ".join(bs[:len(replace_list)]),
        *replace_list,
    )


def get_assign_block(
        k: Union[str, CodeBlock],
        v: Union[str, CodeBlock],
):
    return get_block(
        f"{b0} = {b1}",
        k,
        v,
    )


def get_bool_block(
        k: Union[str, CodeBlock],
        e: Union[str, CodeBlock],
        v: Union[str, CodeBlock],
):
    return get_block(
        f"{b0} {b1} {b2}",
        k,
        e,
        v,
    )


def get_bool_le_block(
        k: Union[str, CodeBlock],
        v: Union[str, CodeBlock],
):
    return get_bool_block(k, "<", v)
